package com.citycloud.ccuap.tc.admin.controller;

import java.io.IOException;
import java.util.Arrays;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.alibaba.druid.support.json.JSONUtils;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.citycloud.ccuap.commons.json.JSONData;
import com.citycloud.ccuap.commons.json.JSONUtil;
import com.citycloud.ccuap.tc.admin.constant.AdminConstant;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Controller;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import com.citycloud.ccuap.commons.application.Application;
import com.citycloud.ccuap.commons.constants.GlobalSysType;
import com.citycloud.ccuap.commons.openapi.service.ISecurityService;
import com.citycloud.ccuap.commons.sys.entity.SysUser;
import com.citycloud.ccuap.commons.sys.user.IUserService;
import com.citycloud.ccuap.commons.web.session.CurrentUser;
import com.citycloud.ccuap.commons.web.session.SessionConstant;
import com.citycloud.ccuap.commons.web.session.SessionManageUtil;
import com.citycloud.ccuap.commons.web.util.ResolveRequest;
import com.citycloud.ccuap.framework.exception.AppAssert;
import com.citycloud.ccuap.tc.admin.feignclient.OAuth2FCService;
import com.citycloud.ccuap.tc.admin.feignclient.TokenInfo;
import com.citycloud.ccuap.tc.common.constant.OAuth2Constant;

import lombok.extern.log4j.Log4j2;
import org.springframework.web.client.RestOperations;
import org.springframework.web.client.RestTemplate;
import springfox.documentation.spring.web.json.Json;

@Log4j2
@Controller
public class ClientController {

	@Value("${security.oauth2.client.client-id}")
	private String clientId;

	@Value("${security.oauth2.client.client-secret}")
	private String clientSecret;

	@Value("${security.oauth2.client.address}")
	private String address;

	@Value("${tc.front.realUrl}")
	private String realUrl;

	@Value("${tc.front.useReal}")
	private boolean useReal;

	@Value("${tc.front.relativeUrl}")
	private String relativeUrl;

	@Autowired
	private BCryptPasswordEncoder bCryptPasswordEncoder;

	@Autowired
	private OAuth2FCService oauth2Service;

	@Autowired
	private IUserService userService;

	@Autowired
	private ISecurityService securityService;

	@Value("${spring.session.timeout:1800}")
	private Long sessionTimeout;
	
	@Value("${tc.authorizationProjectId}")
    private Integer authorizationProjectId;

	@GetMapping("/getCryptPasswordEncoder")
	public @ResponseBody String getCryptPasswordEncoder(@RequestParam("clientId") String clientids) {
		String pass = bCryptPasswordEncoder.encode(clientids);
		return pass;
	}


	public String doGet(String url) {
		String content = null;
		// 创建Httpclient对象
		CloseableHttpClient httpclient = HttpClients.createDefault();

		// 创建http GET请求
		HttpGet httpGet = new HttpGet(url);

		CloseableHttpResponse response = null;
		try {
			// 执行请求
			response = httpclient.execute(httpGet);
			System.out.println(response.getStatusLine());
			// 判断返回状态是否为200
			if (response.getStatusLine().getStatusCode() == 200) {
				content = EntityUtils.toString(response.getEntity(), "UTF-8");
				System.out.println("内容长度：" + content.length());
				System.out.println("内容：" + content);
			}
		} catch (Exception e) {
			e.printStackTrace();

		} finally {
			if (response != null) {
				try {
					response.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			try {
				httpclient.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		return content;
	}
	/**
	 * OAuth2 授权码模式 Authorization Code 该接口用于接收认证服务器推送的授权码，此时该资源服务器作为User-Agent角色
	 * <p>
	 * 同时，又以Client角色，向认证中心请求验证 Authorization Code，最终获取到 Access Token
	 * state传参目前定义:第一个参数为回调地址，第二个参数为scope,，中间逗号给开默认第一个参数必传
	 * 
	 * @return
	 */
	@GetMapping("/get_token_by_code")
	public String getToken(String code, String state, HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

//		HttpHeaders headers = new HttpHeaders();
//		headers.set("Authorization", this.getAuthorizationHeader(this.clientId, this.clientSecret));

		// 配置多个回调地址需要添加回调地址,回调地址需与请求code一致
		String redirectUrl = null;
		AppAssert.notNull(state, "必须传入state！");
		String[] params = state.split(",");
		AppAssert.state(params.length == 3, "state传入格式必须是：回调地址,站点ID,用户ID");

		if (!StringUtils.isEmpty(params[0])) {
			redirectUrl = String.valueOf(params[0]);
		}

		log.debug("code={},clientId={},clientSecret={},redirectUrl={}", code, clientId, clientSecret, redirectUrl);
//		TokenInfo tokenInfo = oauth2Service.token("authorization_code", code, clientId, clientSecret, redirectUrl);
//		log.debug("tokenInfo={}", tokenInfo);



		HttpHeaders headers = new HttpHeaders();
		// headers.set("Authorization", this.getAuthorizationHeader(this.clientId, this.clientSecret));

		StringBuilder sb = new StringBuilder();
		sb.append(address).append("/oauth/token")
				.append("?grant_type=").append("authorization_code")
				.append("&code=").append(code)
				.append("&client_id=").append(this.clientId)
				.append("&client_secret=").append(this.clientSecret)
				.append("&redirect_uri=").append(redirectUrl);

		log.info("--------------------sb:[" + sb + "]");
		log.error("--------------------path[" + address + "]clientId[" + this.clientId + "]code[" + code + "]");

		String result = this.doGet(sb.toString());
		JSONObject relustJson = JSON.parseObject(result);
		log.info("--------------------relustJson:[" + relustJson + "]");
		String scope = null;
		if (StringUtils.isEmpty(params[1])) {
//			scope = tokenInfo.getScope();
			scope = (String) relustJson.get("scope");
			log.debug("scope={}", scope);
		} else {
			scope = params[1];
		}
		Long projectId = new Long(scope);
		Long userId = new Long(params[2]);
		log.debug("userId={}", userId);

		// frontUrl配置为相对路径,获取token后回调的地址通过回调地址给的url前缀来匹配
		// 截取从第8位开始，是去除了http://和https://，因为http://后必须有至少一个的字符，所以8应该没问题,有问题直接联系@author
		// xuhangsong@qq.com
		// 相对地址
		String respRedirectUrl = realUrl;
		// 若回调的地址为空，则无法获取对应回调地址，则userReal无效，只能使用绝对前端地址
		if (!useReal && !StringUtils.isEmpty(redirectUrl)) {
			String prefixUrl = redirectUrl.substring(0, redirectUrl.indexOf(AdminConstant.STR_QUESTION_COLON, 8));
			if (relativeUrl.startsWith(AdminConstant.STR_QUESTION_COLON) || relativeUrl.startsWith(AdminConstant.STR_QUESTION_SLASH)) {
				respRedirectUrl = prefixUrl + relativeUrl;
			} else {
				respRedirectUrl = prefixUrl + AdminConstant.STR_QUESTION_SLASH + relativeUrl;
			}
		}

		// 实现统一平台登录，并关联oauth2的token和统一平台的accesstoken
//		ccuapUserLogonInit(request, tokenInfo.getAccessToken(), projectId, userId);
		ccuapUserLogonInit(request, (String)relustJson.get("access_token"), projectId, userId);

		String realRedirect = "redirect:" + respRedirectUrl + "?access_token=" + (String)relustJson.get("access_token") + "&scope="
				+ scope;

		log.info("权限服务获取token后重定向地址为：realRedirect={}", realRedirect);
		return realRedirect;
	}

	/**
	 * 关联OAuth2 access_token 和 session id
	 *
	 * @param accessToken /oauth/token 接口要返回的 access_token
	 * @param projectId   站点编号
	 * @param userId      登录的用户编号
	 */
	private void ccuapUserLogonInit(HttpServletRequest request, String accessToken, Long projectId, Long userId) {
		String logonIp = ResolveRequest.getIpAddress(request);

		SysUser user = userService.findById(userId);
		CurrentUser currentUser;
		if (authorizationProjectId.longValue() == projectId.longValue()) {
			currentUser = securityService.userLogonInit(user, logonIp);
		} else {
			currentUser = securityService.userLogonInit(projectId, user, logonIp, GlobalSysType.SELF);
		}
		SessionManageUtil.setAttributeInfoSession(request, SessionConstant.CURRENT_USER_KEY, currentUser);

		String sessionId = request.getSession().getId();
		currentUser.setAccessToken(sessionId);

		// 获取session有效期
		StringRedisTemplate redisTemplate = Application.getClassBean(StringRedisTemplate.class);
//		String sessionKey = RedisIndexedSessionRepository.DEFAULT_NAMESPACE + ":sessions:" + sessionId;
//		Long timeout = redisTemplate.getExpire(sessionKey);
		// 此时redis中session还未存储，手动从配置获取
		Long timeout = this.sessionTimeout;

		// 关联OAuth2 access_token 和用户的session id
		redisTemplate.opsForValue().set(OAuth2Constant.DEFAULT_KEY_NAMESPACE + accessToken + ":" + projectId, sessionId, timeout,
				TimeUnit.SECONDS);
	}

//	private String getAuthorizationHeader(String clientId, String clientSecret) {
//		if (clientId == null || clientSecret == null) {
//			log.warn(
//					"Null Client ID or Client Secret detected. Endpoint that requires authentication will reject request with 401 error.");
//		}
//
//		String creds = String.format("%s:%s", clientId, clientSecret);
//
//		try {
//			return "Basic " + new String(Base64.encode(creds.getBytes("UTF-8")));
//		} catch (UnsupportedEncodingException var5) {
//			throw new IllegalStateException("Could not convert String");
//		}
//	}
}
